module jinji.server;

import jinji.common.type;

debug import tame.logger;

version (Mock) {
	import jinji.rpc;

	alias WSRequest = Request;
}
WSClient client;

version (App) {
	import core.sys.windows.windows,
	dast.ws,
	dast.wsrpc,
	wad,
	wad.dfh;

	__gshared {
		WebAppDriver wapp;
		HWND hwnd;
		DropFilesHelper dfh;
		GEventLoop loop;
		StdTime lastCloseTime;
	}

	void initDFH() {
		dfh = DropFilesHelper((hDrop) {
			import jinji.util.string,
			lmpl4d,
			std.array,
			std.string;

			if (!client)
				return;
			const count = DragQueryFile(hDrop, 0xFFFFFFFF, null, 0);
			ubyte[] buf;
			auto p = packer(buf);
			p.pack(0, null);
			foreach (uint i; 0 .. count) {
				const size = DragQueryFile(hDrop, i, null, 0);
				auto szFile = uninitializedArray!(wchar[])(size + 1);
				DragQueryFile(hDrop, i, szFile.ptr, size + 1);
				char[MAX_PATH] utf8 = void;
				try {
					const len = fromStringz(szFile.ptr).toUTF8(utf8);
					p.pack(utf8[0 .. len]);
				} catch (Exception e)
					debug error(e);
			}
			client.send(buf);
		});
		dfh.hide();
	}

	/// 事件循环
	class GEventLoop : EventExecutor {
		override void onWeakUp() @trusted {
			import jinji.rpc;

			MSG msg = void;
			while (PeekMessage(&msg, null, 0, 0, PM_REMOVE)) {
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
			// 5s内没有连接就退出
			if (lastCloseTime &&
				lastCloseTime + 5_000_000_0 < now) {
				ExitProcess(0);
			}
			super.onWeakUp();
		}
	}

	class WSServer(T...) : WSRPCServer!(0x400, T) {
		this() {
			import std.algorithm,
			tame.env : totalCPUs;

			loop = new GEventLoop;
			super(loop);
			static if (is(typeof(initWorkers)))
				initWorkers(max(2, totalCPUs - 1));
		}

		debug (Log) override void run() {
			info("Listening on ", settings.listen);
			if (settings.maxConnections)
				info("Maximum allowed connections: ", settings.maxConnections);
			else
				info("Maximum allowed connections: unlimited");
			super.run();
		}

		override void onOpen(WSClient client, in Request req) {
			hwnd = wapp.getWindow();
			lastCloseTime = StdTime.zero;
		}

		override void onClose(WSClient client) {
			import etc.c.sqlite3,
			jinji.db,
			jinji.rpc,
			jinji.user.service;

			try {
				// 定时释放内存
				if (getST() & 256)
					sqlite3_db_release_memory(db);
				dfh.hide();
				logout(client);
				debug {
				} else
					lastCloseTime = now;
			} catch (Exception e) {
				debug error(e);
			}
		}
	}

	private long getST() @trusted {
		import jinji.rpc;

		static last_st = 0L;
		long st = now;
		return st <= last_st ? (last_st += 100) : (last_st = st);
	}

	unittest {
		assert(getST() != getST());
	}
}

extern (C):

/// 选择文件
@"文件列表"@type("string[]")
@Action void browseFile(ref WSRequest req, @"允许多选"bool multi) {
	version (App) {
		foreach (file; browseFiles(multi, hwnd))
			req.send(file);
	}
}

/// 设置拖放区域
@"文件列表"@type("string[]")
@Action void setDropzone(ref WSRequest req, int x, int y, int w, int h = 0) {
	version (App) {
		import std.windows.syserror : wenforce;

		if (w) {
			client = req.src;
			if (hwnd) {
				RECT rect;
				wenforce(GetWindowRect(hwnd, &rect));
				x += rect.left + GetSystemMetrics(SM_CXFRAME);
				y += rect.top + GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
			}
			wenforce(dfh.setPosition(x, y, w, h));
			wenforce(dfh.show());
		} else if (dfh)
			dfh.hide();
	}
}
